#pragma once

#include <sys/types.h>
#include <sys/socket.h> 
#include <iostream>
#include <string>
#include <memory>
#include <unistd.h>
#include <cstdio>
#include <string.h>
#include <pthread.h>
#include <arpa/inet.h>
#include <netinet/in.h>




#include "log.hpp"
#include "threadPool.hpp"
#include "Task.hpp"




//长连接服务
static void service()
{

}

//短链接服务------将客户端传来的字符串中所有的小写字母变为大写
//参数均为服务端信息
static void change(int sock, const string& clientIp, const uint16_t& clientPort, const string& threadName)
{
    char buffer[1024] ;
    //sock的本质是文件描述符
    ssize_t s = read(sock, buffer, sizeof(buffer) - 1); 
    if( s > 0)
    {
        buffer[s] = 0 ; //将发过来的数据作为字符串处理
        std::cout << threadName << "|" << clientIp << ":" << clientPort << "#" << buffer << std::endl ; 
        std::string messages ;
        char* start = buffer ;
        while (*start)
        {
            char c ; 

            //? ? ? ? ? ? 
            if(islower(*start) ) //判断是否为小写字母
            {
                c = toupper(*start) ; 
            }
            else
            {
                c = *start ; 
            }

            messages.push_back(c);
            start++ ;
        }
        write(sock, messages.c_str(), messages.size());
    }
    else if (s == 0) 
    {
        logMessage(NORMAL, "%s:%d shutdown, me too ", clientIp.c_str(), clientPort);
    }
    else //write 出错则返回 -1
    {
        logMessage(ERROR, "read socket error %s:%d", errno, strerror(errno));
    }

    close(sock);
}

//短链接服务
static void dictOnline()
{

}


class TcpServer
{
private:

uint16_t _port ; //服务端端口号？
std::string _ip; //服务端ip地址？
int _listensock; //监听套接字  ？
std::unique_ptr<ThreadPool<Task>> _threadpool_ptr ; //用智能指针包装的线程池

const static int gbacklog = 20 ; //  ? ? ? ? 


public:

    //填充信息 如ip、端口号 获取线程池指针

    //关于ip地址"0.0.0.0"：0.0.0.0并不是一个真实的的IP地址，它表示本机中所有的IPV4地址。
    //服务器不指定在哪个网卡上监听时，也使用0.0.0.0,这个时候监听本机中所有IP的端口。
    TcpServer(uint16_t port, std::string ip = "0.0.0.0") 
        :_listensock(-1)
        ,_port(port)
        ,_ip(ip)
        ,_threadpool_ptr(ThreadPool<Task>::getThreadPool()) 
    {
        
    }

    // initServer()作用：调用网络通信接口，初始化套接字、绑定、监听 

    //1.关于套接字：创建条件：协议域（ipv4/ipv6等），套接字类型（udp/tcp等），协议（0，自动选择）
    // 套接字本质：文件描述符。 作用：？ ？ ？ 

    //2.关于绑定  条件：需要服务端套接字和一个存有服务端ip、协议域、端口的结构体
    //作用： ？ ？ ？

    void initServer()
    {
        _listensock = socket(AF_INET, SOCK_STREAM, 0);
        if(_listensock < 0)
        {
            logMessage(FATAL,"create socket error, %d:%s", errno , strerror(errno));
            exit(2);
        }
        logMessage(NORMAL, "create socket success, linstensock: %d", _listensock);

        //bind 
        sockaddr_in local ;
        memset(&local, 0, sizeof local);
        local.sin_family = AF_INET ; 
        local.sin_port = htons(_port);
        //写法一: //inet_pton 结合AF_INET条件，将字符串类型的ip地址转为网络字节序的二进制传入local.sin_addr中
        inet_pton(AF_INET, _ip.c_str(), &local.sin_addr);
        //写法二: 
        //inet_aton(_ip.c_str(), &local.sin_addr);
        //写法三：
        //local.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str());

        if(bind(_listensock,(sockaddr*)&local, sizeof local) < 0 )
        {
            logMessage(FATAL, "bind error, %d:%s", errno, strerror(errno));
            exit(3);
        }

        if(listen(_listensock, gbacklog) < 0)
        {
            logMessage(FATAL, "listen error, %d:%s", errno, strerror(errno));
            exit(4);
        }
        
        logMessage(NORMAL, "init server success") ;
    }


    //创建、启动所有线程. 接收服务端请求

    //关于accept。 条件：客户端套接字和用于存储发出请求的服务端的信息的sockaddr_in结构体
    //作用：当一个客户端向服务器发起连接请求时，服务器可以使用accept函数接受该连接请求，并返回一个新的套接字，通过该套接字可以与客户端进行通信。
    void start ()
    {
        //创建、启动所有线程
        _threadpool_ptr->run();
        while( true ) //服务端不关闭
        {
            sockaddr_in src ; 
            socklen_t len = sizeof src ;
            int servicesock = accept(_listensock, (sockaddr*)&src, &len);
            if(servicesock < 0)
            {
                logMessage(ERROR, "accept error %d:%s", errno, strerror(errno));
                continue; 
            }
            //直到接收请求成功才继续向下执行
            uint16_t client_port  = ntohs(src.sin_port);
            std::string client_ip = inet_ntoa(src.sin_addr);
            logMessage(NORMAL, "link success , servicesock: %d | %s : %d | \n", service, client_ip.c_str(), client_port);

            //初始化任务Task类
            Task t(servicesock, client_ip, client_port, change);
            //添加任务进队列。并执行
            _threadpool_ptr->pushTask(t);

        }
    }


    //接收服务端信息(accept)
    ~TcpServer()
    {

    }

};

















